/*
 * sample-common.c
 *
 * Copyright (C) 2014 Ingenic Semiconductor Co.,Ltd
 */

#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#include <imp/imp_log.h>
#include <imp/imp_common.h>
#include <imp/imp_system.h>
#include <imp/imp_framesource.h>
#include <imp/imp_encoder.h>
#include <imp/imp_isp.h>
#include <imp/imp_osd.h>

#include "sample-common.h"

#define TAG "Sample-Common"

static const int S_RC_METHOD = ENC_RC_MODE_CBR;
int direct_switch = 1;
int gosd_enable = 3; /* 1: ipu osd, 2: isp osd, 3: ipu osd and isp osd */

//#define SHOW_FRM_BITRATE
#ifdef SHOW_FRM_BITRATE
#define FRM_BIT_RATE_TIME 2
#define STREAM_TYPE_NUM 3
static int frmrate_sp[STREAM_TYPE_NUM] = { 0 };
static int statime_sp[STREAM_TYPE_NUM] = { 0 };
static int bitrate_sp[STREAM_TYPE_NUM] = { 0 };
#endif

struct chn_conf chn[FS_CHN_NUM] = {
	{
		.index = CH0_INDEX,
		.enable = CHN0_EN,
        .payloadType = PT_H264,
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_NV12,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_PHY_CHANNEL,

			.crop.enable = 1,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH,
			.scaler.outheight = SENSOR_HEIGHT,

			.picWidth = SENSOR_WIDTH,
			.picHeight = SENSOR_HEIGHT,
		   },
		.framesource_chn =	{ DEV_ID_FS, CH0_INDEX, 0},
		.imp_encoder = { DEV_ID_ENC, CH0_INDEX, 0},
	},
	{
		.index = CH1_INDEX,
		.enable = CHN1_EN,
        .payloadType = PT_H264,
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_NV12,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_PHY_CHANNEL,

			.crop.enable = 1,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH_SECOND,
			.scaler.outheight = SENSOR_HEIGHT_SECOND,

			.picWidth = SENSOR_WIDTH_SECOND,
			.picHeight = SENSOR_HEIGHT_SECOND,
		   },
		.framesource_chn =	{ DEV_ID_FS, CH1_INDEX, 0},
		.imp_encoder = { DEV_ID_ENC, CH1_INDEX, 0},
	},
	{
		.index = CH2_INDEX,
		.enable = CHN2_EN,
        .payloadType = PT_H264,
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_NV12,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_PHY_CHANNEL,

			.crop.enable = 1,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH_SECOND,
			.crop.height = SENSOR_HEIGHT_SECOND,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH_SECOND,
			.scaler.outheight = SENSOR_HEIGHT_SECOND,

			.picWidth = SENSOR_WIDTH_SECOND,
			.picHeight = SENSOR_HEIGHT_SECOND,
		   },
		.framesource_chn =	{ DEV_ID_FS, CH2_INDEX, 0},
		.imp_encoder = { DEV_ID_ENC, CH2_INDEX, 0},
	},
	{
		.index = CH3_INDEX,
		.enable = CHN3_EN,
        .payloadType = PT_H264,
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_NV12,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_PHY_CHANNEL,

			.crop.enable = 0,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH,
			.scaler.outheight = SENSOR_HEIGHT,

			.picWidth = SENSOR_WIDTH,
			.picHeight = SENSOR_HEIGHT,
		   },
		.framesource_chn =	{ DEV_ID_FS, CH3_INDEX, 0},
		.imp_encoder = { DEV_ID_ENC, CH3_INDEX, 0},
	},
};

struct chn_conf chn_ext_hsv[1] = {
	{
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_HSV,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_EXT_CHANNEL,

			.crop.enable = 0,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH_SECOND,
			.scaler.outheight = SENSOR_HEIGHT_SECOND,

			.picWidth = SENSOR_WIDTH_SECOND,
			.picHeight = SENSOR_HEIGHT_SECOND,
		},
	},
};

struct chn_conf chn_ext_rgba[1] = {
	{
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_RGBA,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_EXT_CHANNEL,

			.crop.enable = 0,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.scaler.enable = 1,
			.scaler.outwidth = SENSOR_WIDTH_SECOND,
			.scaler.outheight = SENSOR_HEIGHT_SECOND,

			.picWidth = SENSOR_WIDTH_SECOND,
			.picHeight = SENSOR_HEIGHT_SECOND,
		},
	},
};

extern int IMP_Encoder_SetPoolSize(int size);
extern int IMP_OSD_SetPoolSize(int size);

IMPSensorInfo sensor_info;
IMPSensorInfo sensor_infos1;
int sample_system_init()
{
	int ret = 0;

	/* isp osd and ipu osd buffer size set */
	if(1 == gosd_enable) { /* only use ipu osd */
		IMP_OSD_SetPoolSize(512*1024);
	} else if(2 == gosd_enable) { /* only use isp osd */
		IMP_ISP_Tuning_SetOsdPoolSize(512 * 1024);
	}else if(3 == gosd_enable) { /* use ipu osd and isp osd */
		IMP_OSD_SetPoolSize(1024*1024);
		IMP_ISP_Tuning_SetOsdPoolSize(1024 * 1024);
	} else {
		IMP_OSD_SetPoolSize(512*1024);
		IMP_ISP_Tuning_SetOsdPoolSize(512 * 1024);
    }

	memset(&sensor_info, 0, sizeof(IMPSensorInfo));
	memcpy(sensor_info.name, SENSOR_NAME, sizeof(SENSOR_NAME));
	sensor_info.cbus_type = SENSOR_CUBS_TYPE;

	memcpy(sensor_info.i2c.type, SENSOR_NAME, sizeof(SENSOR_NAME));
	sensor_info.i2c.addr = SENSOR_I2C_ADDR;
	sensor_info.i2c.i2c_adapter_id = SENSOR_I2C_ADAPTER_ID;

#ifdef SECSENSOR
	memset(&sensor_infos1, 0, sizeof(IMPSensorInfo));
	memcpy(sensor_infos1.name, SENSOR_NAMES1, sizeof(SENSOR_NAMES1));
	sensor_infos1.cbus_type = SENSOR_CUBS_TYPE;
	sensor_infos1.sensor_id = 1;

	memcpy(sensor_infos1.i2c.type, SENSOR_NAMES1, sizeof(SENSOR_NAMES1));
	sensor_infos1.i2c.addr = SENSOR_I2C_ADDRS1;
	sensor_infos1.i2c.i2c_adapter_id = SENSOR_I2C_ADAPTER_ID;
#endif

	IMP_LOG_DBG(TAG, "sample_system_init start\n");

	ret = IMP_ISP_Open();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to open ISP\n");
		return -1;
	}

	ret = IMP_ISP_AddSensor(&sensor_info);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}

#ifdef SECSENSOR
	ret = IMP_ISP_AddSensor(&sensor_infos1);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}
#endif

	ret = IMP_ISP_EnableSensor();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to EnableSensor\n");
		return -1;
	}

	ret = IMP_System_Init();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_System_Init failed\n");
		return -1;
	}

	/* enable turning, to debug graphics */
	ret = IMP_ISP_EnableTuning();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_ISP_EnableTuning failed\n");
		return -1;
	}
    IMP_ISP_Tuning_SetContrast(128);
    IMP_ISP_Tuning_SetSharpness(128);
    IMP_ISP_Tuning_SetSaturation(128);
    IMP_ISP_Tuning_SetBrightness(128);
#if 1
    ret = IMP_ISP_Tuning_SetISPRunningMode(IMPISP_RUNNING_MODE_DAY);
    if (ret < 0){
        IMP_LOG_ERR(TAG, "failed to set running mode\n");
        return -1;
    }
#endif
#if 0
    ret = IMP_ISP_Tuning_SetSensorFPS(SENSOR_FRAME_RATE_NUM, SENSOR_FRAME_RATE_DEN);
    if (ret < 0){
        IMP_LOG_ERR(TAG, "failed to set sensor fps\n");
        return -1;
    }
#endif
	IMP_LOG_DBG(TAG, "ImpSystemInit success\n");

	return 0;
}

int sample_system_exit()
{
	int ret = 0;

	IMP_LOG_DBG(TAG, "sample_system_exit start\n");


	IMP_System_Exit();

	ret = IMP_ISP_DisableSensor();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to EnableSensor\n");
		return -1;
	}

#ifdef SECSENSOR
	ret = IMP_ISP_DelSensor(&sensor_infos1);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}
#endif

	ret = IMP_ISP_DelSensor(&sensor_info);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}

	ret = IMP_ISP_DisableTuning();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_ISP_DisableTuning failed\n");
		return -1;
	}

	if(IMP_ISP_Close()){
		IMP_LOG_ERR(TAG, "failed to open ISP\n");
		return -1;
	}

	IMP_LOG_DBG(TAG, " sample_system_exit success\n");

	return 0;
}

int sample_framesource_streamon()
{
	int ret = 0, i = 0;
	/* Enable channels */
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			ret = IMP_FrameSource_EnableChn(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_EnableChn(%d) error: %d\n", ret, chn[i].index);
				return -1;
			}
		}
	}
	return 0;
}




int sample_framesource_streamoff()
{
	int ret = 0, i = 0;
	/* Enable channels */
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable){
			ret = IMP_FrameSource_DisableChn(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_DisableChn(%d) error: %d\n", ret, chn[i].index);
				return -1;
			}
		}
	}
	return 0;
}


static void *get_frame(void *args)
{
	int index = (int)args;
	int chnNum = chn[index].index;
	int i = 0, ret = 0;
	IMPFrameInfo *frame = NULL;
	char framefilename[64];
	int fd = -1;

	if (PIX_FMT_NV12 == chn[index].fs_chn_attr.pixFmt) {
		sprintf(framefilename, "frame%dx%d.nv12", chn[index].fs_chn_attr.picWidth, chn[index].fs_chn_attr.picHeight);
	} else {
		sprintf(framefilename, "frame%dx%d.raw", chn[index].fs_chn_attr.picWidth, chn[index].fs_chn_attr.picHeight);
	}

	fd = open(framefilename, O_RDWR | O_CREAT, 0x644);
	if (fd < 0) {
		IMP_LOG_ERR(TAG, "open %s failed:%s\n", framefilename, strerror(errno));
		goto err_open_framefilename;
	}

	ret = IMP_FrameSource_SetFrameDepth(chnNum, chn[index].fs_chn_attr.nrVBs * 2);
	if (ret < 0) {
		IMP_LOG_ERR(TAG, "IMP_FrameSource_SetFrameDepth(%d,%d) failed\n", chnNum, chn[index].fs_chn_attr.nrVBs * 2);
		goto err_IMP_FrameSource_SetFrameDepth_1;
	}

	for (i = 0; i < NR_FRAMES_TO_SAVE; i++) {
		ret = IMP_FrameSource_GetFrame(chnNum, &frame);
		if (ret < 0) {
			IMP_LOG_ERR(TAG, "IMP_FrameSource_GetFrame(%d) i=%d failed\n", chnNum, i);
			goto err_IMP_FrameSource_GetFrame_i;
		}
		if (NR_FRAMES_TO_SAVE/2 == i) {
			if (write(fd, (void *)frame->virAddr, frame->size) != frame->size) {
				IMP_LOG_ERR(TAG, "chnNum=%d write frame i=%d failed\n", chnNum, i);
				goto err_write_frame;
			}
		}
		ret = IMP_FrameSource_ReleaseFrame(chnNum, frame);
		if (ret < 0) {
			IMP_LOG_ERR(TAG, "IMP_FrameSource_ReleaseFrame(%d) i=%d failed\n", chnNum, i);
			goto err_IMP_FrameSource_ReleaseFrame_i;
		}
	}

	IMP_FrameSource_SetFrameDepth(chnNum, 0);

	return (void *)0;

err_IMP_FrameSource_ReleaseFrame_i:
err_write_frame:
	IMP_FrameSource_ReleaseFrame(chnNum, frame);
err_IMP_FrameSource_GetFrame_i:
	goto err_IMP_FrameSource_SetFrameDepth_1;
	IMP_FrameSource_SetFrameDepth(chnNum, 0);
err_IMP_FrameSource_SetFrameDepth_1:
	close(fd);
err_open_framefilename:
	return (void *)-1;
}

int sample_get_frame()
{
	unsigned int i;
	int ret;
	pthread_t tid[FS_CHN_NUM];

	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			ret = pthread_create(&tid[i], NULL, get_frame, (void *)i);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "Create ChnNum%d get_frame failed\n", chn[i].index);
				return -1;
			}
		}
	}

	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			pthread_join(tid[i],NULL);
		}
	}

	return 0;
}

int sample_framesource_init()
{
	int i, ret;

	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			ret = IMP_FrameSource_CreateChn(chn[i].index, &chn[i].fs_chn_attr);
			if(ret < 0){
				IMP_LOG_ERR(TAG, "IMP_FrameSource_CreateChn(chn%d) error !\n", chn[i].index);
				return -1;
			}

			ret = IMP_FrameSource_SetChnAttr(chn[i].index, &chn[i].fs_chn_attr);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_SetChnAttr(chn%d) error !\n",  chn[i].index);
				return -1;
			}
		}
	}

	return 0;
}

int sample_framesource_exit()
{
	int ret,i;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			/*Destroy channel */
			ret = IMP_FrameSource_DestroyChn(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_DestroyChn(%d) error: %d\n", chn[i].index, ret);
				return -1;
			}
		}
	}
	return 0;
}


int sample_jpeg_init()
{
	int i, ret;
	IMPEncoderAttr *enc_attr;
	IMPEncoderCHNAttr channel_attr;
	IMPFSChnAttr *imp_chn_attr_tmp;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			imp_chn_attr_tmp = &chn[i].fs_chn_attr;
			memset(&channel_attr, 0, sizeof(IMPEncoderCHNAttr));
			enc_attr = &channel_attr.encAttr;
			enc_attr->enType = PT_JPEG;
			enc_attr->bufSize = 0;
			enc_attr->profile = 0;
			enc_attr->picWidth = imp_chn_attr_tmp->picWidth;
			enc_attr->picHeight = imp_chn_attr_tmp->picHeight;

			/* Create Channel */
			if(direct_switch == 1) {
				if (0 == chn[i].index) channel_attr.bEnableIvdc = true;
			}

			ret = IMP_Encoder_CreateChn(3 + chn[i].index, &channel_attr);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_CreateChn(%d) error: %d\n",
							chn[i].index, ret);
				return -1;
			}

			/* Resigter Channel */
			ret = IMP_Encoder_RegisterChn(i, 3 + chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_RegisterChn(0, %d) error: %d\n",
							chn[i].index, ret);
				return -1;
			}
		}
	}

	return 0;
}

int sample_encoder_init()
{
	int i, ret, chnNum = 0;
	IMPEncoderAttr *enc_attr;
	IMPEncoderRcAttr *rc_attr;
	IMPFSChnAttr *imp_chn_attr_tmp;
	IMPEncoderCHNAttr channel_attr;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			imp_chn_attr_tmp = &chn[i].fs_chn_attr;
			memset(&channel_attr, 0, sizeof(IMPEncoderCHNAttr));
			enc_attr = &channel_attr.encAttr;
			enc_attr->enType = chn[i].payloadType;
			if ((imp_chn_attr_tmp->picHeight > 1920) || (imp_chn_attr_tmp->picHeight == 1920)) {
				enc_attr->bufSize = imp_chn_attr_tmp->picWidth*imp_chn_attr_tmp->picHeight*3/10;
			} else if ((imp_chn_attr_tmp->picHeight > 1520) || (imp_chn_attr_tmp->picHeight == 1520)) {
				enc_attr->bufSize = imp_chn_attr_tmp->picWidth*imp_chn_attr_tmp->picHeight*3/8;
			} else if ((imp_chn_attr_tmp->picHeight > 1080) || (imp_chn_attr_tmp->picHeight == 1080)) {
				enc_attr->bufSize = imp_chn_attr_tmp->picWidth*imp_chn_attr_tmp->picHeight/2;
			} else {
				enc_attr->bufSize = imp_chn_attr_tmp->picWidth*imp_chn_attr_tmp->picHeight*3/4;
			}
			enc_attr->profile = 1;
			enc_attr->picWidth = imp_chn_attr_tmp->picWidth;
			enc_attr->picHeight = imp_chn_attr_tmp->picHeight;
            if (chn[i].payloadType == PT_JPEG) {
                chnNum = 3 + chn[i].index;
            } else if (chn[i].payloadType == PT_H264) {
                chnNum = chn[i].index;
				enc_attr->profile = -1;
                rc_attr = &channel_attr.rcAttr;
                rc_attr->outFrmRate.frmRateNum = imp_chn_attr_tmp->outFrmRateNum;
                rc_attr->outFrmRate.frmRateDen = imp_chn_attr_tmp->outFrmRateDen;
                rc_attr->maxGop = 2 * rc_attr->outFrmRate.frmRateNum / rc_attr->outFrmRate.frmRateDen;
                if (S_RC_METHOD == ENC_RC_MODE_CBR) {
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_CBR;
                    rc_attr->attrRcMode.attrH264Cbr.outBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH264Cbr.maxQp = 45;
                    rc_attr->attrRcMode.attrH264Cbr.minQp = 15;
                    rc_attr->attrRcMode.attrH264Cbr.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH264Cbr.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH264Cbr.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH264Cbr.adaptiveMode = false;
                    rc_attr->attrRcMode.attrH264Cbr.gopRelation = false;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else if (S_RC_METHOD == ENC_RC_MODE_VBR) {
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_VBR;
                    rc_attr->attrRcMode.attrH264Vbr.maxQp = 45;
                    rc_attr->attrRcMode.attrH264Vbr.minQp = 15;
                    rc_attr->attrRcMode.attrH264Vbr.staticTime = 2;
                    rc_attr->attrRcMode.attrH264Vbr.maxBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH264Vbr.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH264Vbr.changePos = 80;
                    rc_attr->attrRcMode.attrH264Vbr.qualityLvl = 2;
                    rc_attr->attrRcMode.attrH264Vbr.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH264Vbr.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH264Vbr.gopRelation = false;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else if (S_RC_METHOD == ENC_RC_MODE_SMART) {
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_SMART;
                    rc_attr->attrRcMode.attrH264Smart.maxQp = 45;
                    rc_attr->attrRcMode.attrH264Smart.minQp = 15;
                    rc_attr->attrRcMode.attrH264Smart.staticTime = 2;
                    rc_attr->attrRcMode.attrH264Smart.maxBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH264Smart.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH264Smart.changePos = 80;
                    rc_attr->attrRcMode.attrH264Smart.qualityLvl = 2;
                    rc_attr->attrRcMode.attrH264Smart.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH264Smart.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH264Smart.gopRelation = false;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = rc_attr->maxGop - 1;
                    rc_attr->attrHSkip.hSkipAttr.n = 1;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 6;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else { /* fixQp */
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_FIXQP;
                    rc_attr->attrRcMode.attrH264FixQp.qp = 35;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                }
            } else { //PT_H265
                chnNum = chn[i].index;
                rc_attr = &channel_attr.rcAttr;
                rc_attr->outFrmRate.frmRateNum = imp_chn_attr_tmp->outFrmRateNum;
                rc_attr->outFrmRate.frmRateDen = imp_chn_attr_tmp->outFrmRateDen;
                rc_attr->maxGop = 2 * rc_attr->outFrmRate.frmRateNum / rc_attr->outFrmRate.frmRateDen;
                if (S_RC_METHOD == ENC_RC_MODE_CBR) {
                    rc_attr->attrRcMode.attrH265Cbr.maxQp = 45;
                    rc_attr->attrRcMode.attrH265Cbr.minQp = 15;
                    rc_attr->attrRcMode.attrH265Cbr.staticTime = 2;
                    rc_attr->attrRcMode.attrH265Cbr.outBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH265Cbr.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH265Cbr.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH265Cbr.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH265Cbr.flucLvl = 2;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else if (S_RC_METHOD == ENC_RC_MODE_VBR) {
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_VBR;
                    rc_attr->attrRcMode.attrH265Vbr.maxQp = 45;
                    rc_attr->attrRcMode.attrH265Vbr.minQp = 15;
                    rc_attr->attrRcMode.attrH265Vbr.staticTime = 2;
                    rc_attr->attrRcMode.attrH265Vbr.maxBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH265Vbr.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH265Vbr.changePos = 80;
                    rc_attr->attrRcMode.attrH265Vbr.qualityLvl = 2;
                    rc_attr->attrRcMode.attrH265Vbr.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH265Vbr.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH265Vbr.flucLvl = 2;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else if (S_RC_METHOD == ENC_RC_MODE_SMART) {
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_SMART;
                    rc_attr->attrRcMode.attrH265Smart.maxQp = 45;
                    rc_attr->attrRcMode.attrH265Smart.minQp = 15;
                    rc_attr->attrRcMode.attrH265Smart.staticTime = 2;
                    rc_attr->attrRcMode.attrH265Smart.maxBitRate = BITRATE_720P_Kbs;
                    rc_attr->attrRcMode.attrH265Smart.iBiasLvl = 0;
                    rc_attr->attrRcMode.attrH265Smart.changePos = 80;
                    rc_attr->attrRcMode.attrH265Smart.qualityLvl = 2;
                    rc_attr->attrRcMode.attrH265Smart.frmQPStep = 3;
                    rc_attr->attrRcMode.attrH265Smart.gopQPStep = 15;
                    rc_attr->attrRcMode.attrH265Smart.flucLvl = 2;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = rc_attr->maxGop - 1;
                    rc_attr->attrHSkip.hSkipAttr.n = 1;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 6;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                } else { /* fixQp */
                    rc_attr->attrRcMode.rcMode = ENC_RC_MODE_FIXQP;
                    rc_attr->attrRcMode.attrH265FixQp.qp = 35;

                    rc_attr->attrHSkip.hSkipAttr.skipType = IMP_Encoder_STYPE_N1X;
                    rc_attr->attrHSkip.hSkipAttr.m = 0;
                    rc_attr->attrHSkip.hSkipAttr.n = 0;
                    rc_attr->attrHSkip.hSkipAttr.maxSameSceneCnt = 0;
                    rc_attr->attrHSkip.hSkipAttr.bEnableScenecut = 0;
                    rc_attr->attrHSkip.hSkipAttr.bBlackEnhance = 0;
                    rc_attr->attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N1X;
                }
			}

			if(direct_switch == 1) {
				if (0 == chnNum) channel_attr.bEnableIvdc = true;
			}

			ret = IMP_Encoder_CreateChn(chnNum, &channel_attr);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_CreateChn(%d) error !\n", chnNum);
				return -1;
			}

			ret = IMP_Encoder_RegisterChn(chn[i].index, chnNum);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_RegisterChn(%d, %d) error: %d\n", chn[i].index, chnNum, ret);
				return -1;
			}
		}
	}

	return 0;
}

int sample_encoder_exit(void)
{
    int ret = 0, i = 0, chnNum = 0;
    IMPEncoderCHNStat chn_stat;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
            if (chn[i].payloadType == PT_JPEG) {
                chnNum = 3 + chn[i].index;
            } else {
                chnNum = chn[i].index;
            }
            memset(&chn_stat, 0, sizeof(IMPEncoderCHNStat));
            ret = IMP_Encoder_Query(chnNum, &chn_stat);
            if (ret < 0) {
                IMP_LOG_ERR(TAG, "IMP_Encoder_Query(%d) error: %d\n", chnNum, ret);
                return -1;
            }

            if (chn_stat.registered) {
                ret = IMP_Encoder_UnRegisterChn(chnNum);
                if (ret < 0) {
                    IMP_LOG_ERR(TAG, "IMP_Encoder_UnRegisterChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }

                ret = IMP_Encoder_DestroyChn(chnNum);
                if (ret < 0) {
                    IMP_LOG_ERR(TAG, "IMP_Encoder_DestroyChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }
            }
        }
    }

    return 0;
}
